package com.wang.builder;

import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MemberValuePair;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.expr.ThisExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.javadoc.Javadoc;
import com.github.javaparser.utils.SourceRoot;
import com.wang.model.ApiInfo;
import com.wang.model.MethodInfo;

import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * 方法调用图构建器：扫描源码，解析方法调用关系和Controller接口信息
 *
 * @author 13741
 */
public class CallGraphBuilder {
    // 项目源码根路径
    private final String sourceRootPath;
    // 基础包名（如 com.example）
    private final String basePackage;

    // 构建结果存储  所有方法：签名→MethodInfo
    private final Map<String, MethodInfo> allMethods = new HashMap<>();
    // 调用关系：调用者→被调用者
    private final Map<MethodInfo, Set<MethodInfo>> methodCallGraph = new HashMap<>();
    // Controller接口：方法→API信息
    private final Map<MethodInfo, ApiInfo> controllerApis = new HashMap<>();

    public CallGraphBuilder(String sourceRootPath, String basePackage) {
        this.sourceRootPath = sourceRootPath;
        this.basePackage = basePackage;
    }

    /**
     * 执行构建流程：扫描源码并解析方法调用关系
     */
    public void build() {
        SourceRoot sourceRoot = new SourceRoot(Paths.get(sourceRootPath));
        try {
            // 遍历并解析所有源码文件
            sourceRoot.parse("", (relativePath, absolutePath, result) -> {
                processCompilationUnit(result);
                return SourceRoot.Callback.Result.DONT_SAVE;
            });
            System.out.println("调用图构建完成：方法总数=" + allMethods.size() + "，Controller接口数=" + controllerApis.size());
        } catch (Exception e) {
            System.err.println("构建调用图失败：" + e.getMessage());
        }
    }

    /**
     * 处理单个编译单元（Java文件）
     */
    private void processCompilationUnit(ParseResult<CompilationUnit> result) {
        if (!result.isSuccessful()) {
            return;
        }

        CompilationUnit cu = result.getResult().orElse(null);
        if (cu == null) {
            return;
        }

        // 获取包名并过滤非目标包的类
        String packageName = cu.getPackageDeclaration().map(pd -> pd.getName().asString()).orElse("");
        if (!packageName.startsWith(basePackage)) {
            return;
        }

        // 解析所有类声明
        for (TypeDeclaration<?> type : cu.getTypes()) {
            if (type instanceof ClassOrInterfaceDeclaration) {
                ClassOrInterfaceDeclaration classDecl = (ClassOrInterfaceDeclaration) type;
                new ClassVisitor(packageName, classDecl).visit(classDecl, null);
            }
        }
    }

    /**
     * 类解析访问器：处理类中的方法和注解
     */
    private class ClassVisitor extends VoidVisitorAdapter<Void> {
        private final String packageName;
        private final String className;
        // 是否为Controller类
        private final boolean isController;
        // 类级别的RequestMapping路径
        private final String classRequestMapping;

        public ClassVisitor(String packageName, ClassOrInterfaceDeclaration classDecl) {
            this.packageName = packageName;
            this.className = classDecl.getNameAsString();
            this.isController = isControllerClass(classDecl);
            this.classRequestMapping = extractClassRequestMapping(classDecl);
        }

        /**
         * 解析方法：提取方法信息和调用关系
         */
        @Override
        public void visit(MethodDeclaration method, Void arg) {
            String fullClassName = packageName + "." + className;
            MethodInfo currentMethod = new MethodInfo(fullClassName, method.getNameAsString());
            allMethods.put(currentMethod.getFullName(), currentMethod);

            // 处理Controller方法的API信息
            if (isController && isRequestMappingMethod(method)) {
                ApiInfo apiInfo = extractApiInfo(method);
                controllerApis.put(currentMethod, apiInfo);
            }

            // 收集方法调用关系
            MethodCallCollector collector = new MethodCallCollector(method);
            collector.visit(method, null);
            methodCallGraph.put(currentMethod, collector.getCalledMethods());

            super.visit(method, arg);
        }

        /**
         * 提取Controller方法的API信息
         */
        private ApiInfo extractApiInfo(MethodDeclaration method) {
            String methodPath = extractMethodMappingPath(method);
            String fullPath = joinPaths(classRequestMapping, methodPath);
            String httpMethod = getHttpMethod(method);
            String description = extractMethodComment(method);
            return new ApiInfo(fullPath, httpMethod, description);
        }
    }

    /**
     * 方法调用收集器：提取方法中调用的其他方法
     */
    private static class MethodCallCollector extends VoidVisitorAdapter<Void> {
        private final Set<MethodInfo> calledMethods = new HashSet<>();
        // 存储「成员变量名→完整类名」映射（@Autowired/@Resource 注入）
        private final Map<String, String> fieldTypeMap = new HashMap<>();
        // 当前解析的方法（用于获取所在类、导入语句等上下文）
        private final MethodDeclaration currentMethod;
        // 当前方法所在类的完整包名（提前缓存，避免重复查找）
        private final String currentClassFullName;
        // 当前类所在的包名（如 com.example.service）
        private String currentPackageName;

        // 构造方法：传入当前解析的方法，初始化注入变量映射
        public MethodCallCollector(MethodDeclaration currentMethod) {
            this.currentMethod = currentMethod;
            // 提前缓存当前类的完整包名   包名 + 类名 （如 com.example.service.OrderService）
            this.currentClassFullName = getCurrentClassFullName();
            // 解析当前类所在的包名
            this.currentPackageName = getCurrentPackageName();
            // 解析注入变量（兼容 @Autowired 和 @Resource）
            this.parseInjectedFields();
        }

        // 新增：获取当前类所在的包名
        private String getCurrentPackageName() {
            Optional<ClassOrInterfaceDeclaration> classOpt = this.currentMethod.findAncestor(ClassOrInterfaceDeclaration.class);
            if (!classOpt.isPresent()) {
                return "";
            }
            Optional<CompilationUnit> cuOpt = classOpt.get().findAncestor(CompilationUnit.class);
            // 从 CompilationUnit 中提取包名（如 com.example.service）
            return cuOpt.map(cu -> cu.getPackageDeclaration().map(pd -> pd.getName().asString()).orElse("")).orElse("");
        }

        // 获取当前方法所在类的完整包名
        private String getCurrentClassFullName() {
            Optional<ClassOrInterfaceDeclaration> classOpt = this.currentMethod.findAncestor(ClassOrInterfaceDeclaration.class);
            if (!classOpt.isPresent()) {
                return "UnknownClass";
            }
            ClassOrInterfaceDeclaration currentClass = classOpt.get();
            // 获取包名（从 CompilationUnit 中解析）
            Optional<CompilationUnit> cuOpt = currentClass.findAncestor(CompilationUnit.class);
            String packageName = cuOpt.map(cu -> cu.getPackageDeclaration().map(pd -> pd.getName().asString()).orElse("")).orElse("");
            // 拼接完整类名（包名 + 类名）
            return packageName.isEmpty() ? currentClass.getNameAsString() : packageName + "." + currentClass.getNameAsString();
        }

        /**
         * 解析当前类中 @Autowired 或 @Resource 注入的成员变量
         * Java 8 兼容：显式声明变量类型，使用基础 Optional 方法
         */
        private void parseInjectedFields() {
            // 1. 获取当前方法所在的类（Java 8 Optional 操作）
            Optional<ClassOrInterfaceDeclaration> classOpt = this.currentMethod.findAncestor(ClassOrInterfaceDeclaration.class);
            if (!classOpt.isPresent()) {
                return; // 未找到类，直接返回
            }
            ClassOrInterfaceDeclaration currentClass = classOpt.get();

            // 2. 遍历类中的所有成员变量
            List<FieldDeclaration> fields = currentClass.getFields();
            for (FieldDeclaration field : fields) {
                // 3. 仅处理带 @Autowired 或 @Resource 注解的变量
                if (!isFieldHasInjectionAnnotation(field)) {
                    continue;
                }

                // 4. 获取变量类型（如 OrderService）和变量名（如 orderService）
                String fieldTypeName = field.getElementType().asString();
                String fieldName = field.getVariables().get(0).getNameAsString();

                // 5. 从导入语句中解析变量类型的完整包名
                String fullFieldClassName = getFullClassNameFromImport(currentClass, fieldTypeName);
                if ("UnknownClass".equals(fullFieldClassName)) {
                    fullFieldClassName = currentPackageName + "." + fieldTypeName;
                }
                fieldTypeMap.put(fieldName, fullFieldClassName);
                System.out.println("解析到注入变量：" + fieldName + " → " + fullFieldClassName);
            }
        }

        /**
         * 判断字段是否有 @Autowired 或 @Resource 注解（Java 8 流操作兼容）
         */
        private boolean isFieldHasInjectionAnnotation(FieldDeclaration field) {
            List<AnnotationExpr> annotations = field.getAnnotations();
            for (AnnotationExpr ann : annotations) {
                String annName = ann.getName().asString();
                // 匹配 @Autowired（springframework）或 @Resource（javax.annotation）
                if (annName.equals("Autowired") || annName.endsWith(".Autowired")
                        || annName.equals("Resource") || annName.endsWith(".Resource")) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 从导入语句中获取「简单类名」对应的「完整包名」（Java 8 兼容）
         */
        private String getFullClassNameFromImport(ClassOrInterfaceDeclaration currentClass, String simpleClassName) {
            // 1. 获取当前类所在的 Java 文件（CompilationUnit）
            Optional<CompilationUnit> cuOpt = currentClass.findAncestor(CompilationUnit.class);
            if (!cuOpt.isPresent()) {
                return "UnknownClass";
            }
            CompilationUnit cu = cuOpt.get();

            // 2. 遍历导入语句，匹配简单类名
            List<ImportDeclaration> imports = cu.getImports();
            for (ImportDeclaration imp : imports) {
                String importFullName = imp.getName().asString();
                // 提取导入语句的最后一段（如 com.example.service.OrderService → OrderService）
                String importSimpleName = importFullName.substring(importFullName.lastIndexOf(".") + 1);
                if (importSimpleName.equals(simpleClassName)) {
                    return importFullName; // 匹配成功，返回完整包名
                }
            }

            // 3. 特殊处理：Java 核心类（无需导入，如 String、System）
            if ("String".equals(simpleClassName)) {
                return "java.lang.String";
            } else if ("System".equals(simpleClassName)) {
                return "java.lang.System";
            } else if ("Arrays".equals(simpleClassName)) {
                return "java.util.Arrays";
            }

            // 4. 未找到导入语句，返回未知
            return "UnknownClass";
        }

        /**
         * 核心：解析方法调用（支持注入变量、静态方法）
         * Java 8 兼容：替换 switch 表达式为 switch 语句，显式声明变量
         */
        @Override
        public void visit(MethodCallExpr methodCall, Void arg) {
            super.visit(methodCall, arg);
            String methodName = methodCall.getName().asString();
            String className = "UnknownClass"; // 默认为未知类

            // 1. 处理有调用者的情况（如 orderService.createOrder()、StaticUtil.doSomething()）
            if (methodCall.getScope().isPresent()) {
                Expression scope = methodCall.getScope().get();
                if (scope instanceof NameExpr) {
                    // 场景1：有显式名称的调用（如 orderService.createOrder()、StaticUtil.doSomething()）
                    String callerVarName = ((NameExpr) scope).getNameAsString();
                    // 优先匹配注入变量（@Autowired/@Resource）
                    if (fieldTypeMap.containsKey(callerVarName)) {
                        className = fieldTypeMap.get(callerVarName);
                    } else {
                        // 匹配静态方法调用（如 StaticUtil.doSomething()）
                        className = parseStaticCallClassName(callerVarName);
                    }
                } else if (scope instanceof ThisExpr) {
                    // 新增场景2：this 调用（如 this.methodB()）→ 本类方法
                    className = this.currentClassFullName;
                }
            } else {
                // 无 scope 的情况：先查静态导入，再查本类方法（解决冲突核心）
                String staticImportClass = parseStaticImportMethod(methodName);
                if (!"UnknownClass".equals(staticImportClass)) {
                    // 场景A：静态导入方法（如 formatDate() 来自 StaticUtil）
                    className = staticImportClass;
                } else {
                    // 场景B：本类方法（如 methodB() 是当前类的方法）
                    className = this.currentClassFullName;
                }
            }

            // 3. 添加被调用方法的信息
            calledMethods.add(new MethodInfo(className, methodName));
        }

        /**
         * 解析带类名的静态调用（如 StaticUtil.doSomething()）
         * Java 8 兼容：使用 switch 语句替代表达式
         */
        private String parseStaticCallClassName(String simpleClassName) {
            // 1. 先从导入语句找完整包名
            Optional<ClassOrInterfaceDeclaration> classOpt = this.currentMethod.findAncestor(ClassOrInterfaceDeclaration.class);
            if (classOpt.isPresent()) {
                Optional<CompilationUnit> cuOpt = classOpt.get().findAncestor(CompilationUnit.class);
                if (cuOpt.isPresent()) {
                    List<ImportDeclaration> imports = cuOpt.get().getImports();
                    for (ImportDeclaration imp : imports) {
                        String importFullName = imp.getName().asString();
                        String importSimpleName = importFullName.substring(importFullName.lastIndexOf(".") + 1);
                        if (importSimpleName.equals(simpleClassName)) {
                            return importFullName;
                        }
                    }
                }
            }

            // 2. 新增：尝试同包类推断（无导入时，拼接当前包名）
            if (!this.currentPackageName.isEmpty()) {
                // 同包类完整类名 = 当前包名 + 简单类名（如 com.example.service + OrderService）
                return this.currentPackageName + "." + simpleClassName;
            }

            // 3. 未找到导入时，处理常见静态类（Java 8 switch 语句）
            String fullClassName;
            switch (simpleClassName) {
                case "System":
                    fullClassName = "java.lang.System";
                    break;
                case "Arrays":
                    fullClassName = "java.util.Arrays";
                    break;
                case "Collections":
                    fullClassName = "java.util.Collections";
                    break;
                default:
                    fullClassName = simpleClassName; // 自定义静态类，需确保导入语句存在
                    break;
            }
            return fullClassName;
        }

        /**
         * 解析静态导入的方法（如 import static com.example.util.StaticUtil.formatDate;）
         */
        private String parseStaticImportMethod(String methodName) {
            Optional<ClassOrInterfaceDeclaration> classOpt = this.currentMethod.findAncestor(ClassOrInterfaceDeclaration.class);
            if (!classOpt.isPresent()) {
                return "UnknownClass";
            }

            Optional<CompilationUnit> cuOpt = classOpt.get().findAncestor(CompilationUnit.class);
            if (!cuOpt.isPresent()) {
                return "UnknownClass";
            }

            // 遍历静态导入语句
            List<ImportDeclaration> imports = cuOpt.get().getImports();
            for (ImportDeclaration imp : imports) {
                if (imp.isStatic()) { // 仅处理静态导入
                    String importFullName = imp.getName().asString();
                    // 静态导入格式：com.example.util.StaticUtil.formatDate
                    if (importFullName.endsWith("." + methodName)) {
                        // 截取类名（去掉方法名部分）
                        return importFullName.substring(0, importFullName.lastIndexOf("."));
                    }
                }
            }

            return "UnknownClass";
        }

        /**
         * 获取收集到的被调用方法列表（返回副本，避免外部修改）
         */
        public Set<MethodInfo> getCalledMethods() {
            return new HashSet<>(this.calledMethods);
        }
    }

    // ------------------------------ 工具方法 ------------------------------

    /**
     * 判断是否为Controller类（含@Controller或@RestController注解）
     */
    private boolean isControllerClass(ClassOrInterfaceDeclaration cls) {
        return hasAnnotation(cls, "Controller") || hasAnnotation(cls, "RestController");
    }

    /**
     * 提取类级别的@RequestMapping路径
     */
    private String extractClassRequestMapping(ClassOrInterfaceDeclaration cls) {
        return cls.getAnnotationByName("RequestMapping").map(this::extractAnnotationValue).orElse("");
    }

    /**
     * 判断是否为请求映射方法（含@RequestMapping及派生注解）
     */
    private boolean isRequestMappingMethod(MethodDeclaration method) {
        return method.getAnnotations().stream().anyMatch(ann -> isSpringMappingAnnotation(ann.getName().asString()));
    }

    /**
     * 判断是否为Spring的映射注解（如@GetMapping、@PostMapping等）
     */
    private boolean isSpringMappingAnnotation(String annotationName) {
        String[] mappings = {"RequestMapping", "GetMapping", "PostMapping", "PutMapping", "DeleteMapping"};
        for (String mapping : mappings) {
            if (annotationName.equals(mapping) || annotationName.endsWith("." + mapping)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取HTTP方法类型（GET/POST等）
     */
    private String getHttpMethod(MethodDeclaration method) {
        for (AnnotationExpr ann : method.getAnnotations()) {
            String name = ann.getName().asString();
            if (name.endsWith("GetMapping")) {
                return "GET";
            }
            if (name.endsWith("PostMapping")) {
                return "POST";
            }
            if (name.endsWith("PutMapping")) {
                return "PUT";
            }
            if (name.endsWith("DeleteMapping")) {
                return "DELETE";
            }
        }
        return "UNKNOWN";
    }

    /**
     * 提取方法级别的映射路径
     */
    private String extractMethodMappingPath(MethodDeclaration method) {
        for (AnnotationExpr ann : method.getAnnotations()) {
            if (isSpringMappingAnnotation(ann.getName().asString())) {
                return extractAnnotationValue(ann);
            }
        }
        return "";
    }

    /**
     * 提取注解的字符串值（处理@RequestMapping的value或path属性）
     */
    private String extractAnnotationValue(AnnotationExpr ann) {
        if (ann instanceof SingleMemberAnnotationExpr) {
            Expression value = ((SingleMemberAnnotationExpr) ann).getMemberValue();
            if (value instanceof StringLiteralExpr) {
                return ((StringLiteralExpr) value).getValue();
            }
        } else if (ann instanceof NormalAnnotationExpr) {
            for (MemberValuePair pair : ((NormalAnnotationExpr) ann).getPairs()) {
                if ("value".equals(pair.getNameAsString()) || "path".equals(pair.getNameAsString())) {
                    Expression value = pair.getValue();
                    if (value instanceof StringLiteralExpr) {
                        return ((StringLiteralExpr) value).getValue();
                    }
                }
            }
        }
        return "";
    }

    /**
     * 提取Swagger的@ApiOperation描述
     */
    private String extractApiOperationDescription(MethodDeclaration method) {
        return method.getAnnotationByName("ApiOperation").map(ann -> {
            if (ann instanceof NormalAnnotationExpr) {
                for (MemberValuePair pair : ((NormalAnnotationExpr) ann).getPairs()) {
                    if ("value".equals(pair.getNameAsString())) {
                        Expression value = pair.getValue();
                        if (value instanceof StringLiteralExpr) {
                            return ((StringLiteralExpr) value).getValue();
                        }
                    }
                }
            }
            return "No description";
        }).orElse("No description");
    }



    private String extractJavadocFirstLine(MethodDeclaration method) {
        Optional<Javadoc> javadocOpt = method.getJavadoc();
        if (javadocOpt.isPresent()) {
            Javadoc javadoc = javadocOpt.get();
            // 将文档注释转换为纯文本（去除/**、*/标记）
            String fullComment = javadoc.getDescription().toText()
                    .replaceAll("/\\*+", "") // 去除开头的/*
                    .replaceAll("\\*+/", "") // 去除结尾的*/
                    .replaceAll("^\\s*\\*\\s*", ""); // 去除每行开头的*和空格

            // 按换行符分割为多行
            String[] lines = fullComment.split("\n");
            // 遍历行，返回第一行非空内容
            for (String line : lines) {
                String trimmedLine = line.trim();
                if (!trimmedLine.isEmpty()) {
                    return trimmedLine;
                }
            }
        }
        return ""; // 无有效文档注释
    }

    /**
     * 提取方法的注释描述（仅保留文档注释第一行，其次单行注释/Swagger）
     */
    private String extractMethodComment(MethodDeclaration method) {
        // 1. 优先提取文档注释的第一行
        String javadocFirstLine = extractJavadocFirstLine(method);
        if (!javadocFirstLine.isEmpty()) {
            return javadocFirstLine;
        }

        // 2. 若文档注释不存在，提取紧邻的单行注释
        String lineComment = extractLineComment(method);
        if (!lineComment.isEmpty()) {
            return lineComment;
        }

        // 3. 最后 fallback 到 Swagger 的@ApiOperation
        return extractApiOperationDescription(method);
    }

    // 原有单行注释提取方法保持不变
    private String extractLineComment(MethodDeclaration method) {
        List<Comment> comments = method.getAllContainedComments();
        for (Comment comment : comments) {
            if (comment instanceof LineComment) {
                String content = comment.getContent().trim();
                if (!content.isEmpty()) {
                    return content;
                }
            }
        }
        return "";
    }

    /**
     * 拼接类路径和方法路径（处理斜杠问题）
     */
    private String joinPaths(String classPath, String methodPath) {
        String fullPath = normalizePath(classPath) + normalizePath(methodPath);
        // 合并连续斜杠
        return fullPath.replaceAll("/{2,}", "/");
    }

    /**
     * 标准化路径（确保以斜杠开头）
     */
    private String normalizePath(String path) {
        if (path == null || path.trim().isEmpty()) {
            return "";
        }
        return path.startsWith("/") ? path : "/" + path;
    }

    /**
     * 检查类是否包含指定注解
     */
    private boolean hasAnnotation(ClassOrInterfaceDeclaration cls, String annotationName) {
        return cls.getAnnotations().stream().anyMatch(ann -> {
            String name = ann.getName().asString();
            return name.equals(annotationName) || name.endsWith("." + annotationName);
        });
    }

    // ------------------------------ Getter方法 ------------------------------

    public Map<String, MethodInfo> getAllMethods() {
        // 返回副本避免外部修改
        return new HashMap<>(allMethods);
    }

    public Map<MethodInfo, Set<MethodInfo>> getMethodCallGraph() {
        return new HashMap<>(methodCallGraph);
    }

    public Map<MethodInfo, ApiInfo> getControllerApis() {
        return new HashMap<>(controllerApis);
    }
}
